Show answered questions in the thread timeline#4506
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR introduces a new feature with new UI components (UserInputTimelineRow, UserInputAnswer), new data structures, and significant logic for displaying Q&A exchanges in the thread timeline. New user-facing features of this scope warrant human review. You can customize Macroscope's approvability policy. Learn more. |
cec9f42 to
f7eaa00
Compare
#44) Source: pingdotgg#4506 Source SHA: f7eaa00 Imported unchanged as one candidate provenance commit.
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
A clarifying-question round trip left no readable trace in the thread. The
`user-input.requested` / `user-input.resolved` activities carry the questions
and the answers in their payloads, but the timeline rendered them as two
contentless rows ("User input requested" / "User input submitted"), and the
`AskUserQuestion` tool row beside them showed only truncated request JSON.
Both were also collapsed behind the work-group toggle and the turn fold, so
scrolling back gave no record of what was asked or what was chosen.
Merge the request and its resolution into one Q&A entry, render it as a card
with the question header, the question, and the picked option(s) or free-text
answer, and keep it out of the work-group collapse and the turn fold. The
alternatives stay one click away behind "Show options". The duplicate
`AskUserQuestion` tool rows are dropped, mirroring how `ExitPlanMode` rows are
already suppressed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
OpenCode joins a multi-select reply into one ", "-separated string.
Splitting on every comma corrupted two cases: a free-text answer that
happens to contain a comma was chopped into fragments, and an option label
containing a comma ("Small, safe change") never matched again. Consume the
value label by label, longest first, and fall back to treating it as free
text when it is not a run of option labels.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
f7eaa00 to
fd30c91
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fd30c91. Configure here.
| } | ||
| // `tool.started` lands before any input streams, leaving only the detail prefix. | ||
| return asTrimmedString(payload?.detail)?.startsWith("AskUserQuestion:") === true; | ||
| } |
There was a problem hiding this comment.
Tool row hidden without Q&A
Medium Severity
isUserInputToolActivity always drops AskUserQuestion tool rows, but a structured userInput card is only created when requestId is present and parseUserInputQuestions succeeds. When that fails, the timeline keeps only a contentless generic request row, so the question JSON that previously lived on the tool row is gone.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit fd30c91. Configure here.
| ...asked, | ||
| label: userInputWorkLogLabel(questions), | ||
| userInput: { ...asked.userInput, answered: true, questions }, | ||
| }; |
There was a problem hiding this comment.
Awaiting state ignores stale failures
Low Severity
deriveWorkLogEntries never clears or marks a clarifying-question card when provider.user-input.respond.failed reports a stale pending request. derivePendingUserInputs already drops that prompt, so the timeline can keep showing Awaiting your answer after the composer has moved on.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit fd30c91. Configure here.
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts
…meline) # Conflicts: # apps/web/src/components/chat/MessagesTimeline.logic.test.ts # apps/web/src/components/chat/MessagesTimeline.logic.ts


What Changed
A clarifying-question round trip (Claude's
AskUserQuestion, and the sameuser-input.*events from the other providers) now renders as a single Q&A cardin the thread timeline: the question header, the question, and the option(s) the
user picked — or their free-text answer. The alternatives stay one click away
behind "Show options".
deriveWorkLogEntriesmergesuser-input.requestedwith itsuser-input.resolvedinto one entry (entry.userInput), resolving each answeragainst the question's options so a picked label and an "Other" answer render
differently. A resolution whose request has scrolled out of the activity window
still shows its answer.
the settled-turn fold hides them — the exchange records a decision, so it stays
readable in history.
AskUserQuestiontool rows are dropped, the same wayExitPlanModerows are already suppressed.Why
The answers were already persisted —
user-input.resolvedcarries{"answers": {"<question>": "<label>"}}— but nothing rendered them. Thetimeline showed two contentless rows,
User input requestedandUser input submitted, neither expandable, plus aTool callrow whose onlycontent was truncated request JSON (
AskUserQuestion: {"questions":[{"header"...).Both sat inside the work-group collapse (
MAX_VISIBLE_WORK_LOG_ENTRIES = 1) andthe turn fold, so in practice a finished thread showed no trace of the question
or the answer at all.
That is a real gap in the transcript: the interactive prompt lives in the
composer and disappears once answered, so the timeline is the only lasting record
of what the agent asked and what the user decided.
UI Changes
Same seeded thread in every shot: two questions (one single-select answered with
free text, one multi-select), plus the
AskUserQuestiontool rows Claude emitsalongside the events.
Before — settled turn, as you first see it. The exchange is entirely absent:
Before — after expanding both the turn fold and the work group. Two empty
rows and a JSON dump; the answers appear nowhere:
After — settled turn, no expansion needed:
After — "Show options" reveals the alternatives, with the picked ones highlighted:
After — turn fold expanded: the card sits inline where the question was
asked, surrounding tool calls still collapse as before, and the raw
AskUserQuestionrow is gone:Scope note:
apps/mobile/src/lib/threadActivity.tscarries its own copy of thisderivation and has the same gap. Left out to keep this PR focused on one surface.
Validation
Plus an integrated pass in a browser against an isolated dev environment
(
vp run dev --home-dir …) with the seeded thread above — that is where thescreenshots come from.
Checklist
Note
Low Risk
Web-only chat timeline and session-logic presentation changes with broad test coverage; no auth, API, or data-persistence changes.
Overview
Clarifying-question exchanges now show up as persistent Q&A cards in the thread timeline instead of disappearing into collapsed work logs and settled-turn folds.
deriveWorkLogEntriesmergesuser-input.requested/user-input.resolvedinto one work entry with structureduserInput(questions, selected options, free-text answers), filters duplicateAskUserQuestiontool rows, and handles edge cases like orphaned resolutions and OpenCode’s comma-joined multi-select strings.Timeline derivation adds a dedicated
user-inputrow so these entries are not grouped with tool work or hidden by turn folding.MessagesTimelinerenders the card with question text, the chosen answer (or “Awaiting your answer”), and an optional “Show options” toggle for alternatives.Reviewed by Cursor Bugbot for commit fd30c91. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Show answered clarifying questions as Q&A cards in the chat timeline
'user-input'row type to the timeline that renders clarifying-question exchanges as a styled Q&A card showing questions, selected answers, and an optional toggle for unchosen options.deriveWorkLogEntriesin session-logic.ts to mergeuser-input.requestedanduser-input.resolvedactivities into a single structured entry, dropping duplicateAskUserQuestiontool rows.deriveTurnFoldsto keep clarifying-question entries visible even when their turn is collapsed.Macroscope summarized fd30c91.